package com.hsh.gaoqianlianmeng.service.impl;


import com.hsh.gaoqianlianmeng.common.Result;
import com.hsh.gaoqianlianmeng.comparator.YangComparator;
import com.hsh.gaoqianlianmeng.constants.DateTimeConstants;
import com.hsh.gaoqianlianmeng.constants.ShopConstants;
import com.hsh.gaoqianlianmeng.constants.YangConstants;
import com.hsh.gaoqianlianmeng.constants.filepath.YangBGPathConstants;
import com.hsh.gaoqianlianmeng.domain.*;
import com.hsh.gaoqianlianmeng.service.ShopService;
import com.hsh.gaoqianlianmeng.service.YangBGService;
import com.hsh.gaoqianlianmeng.utils.DateUtils;
import com.hsh.gaoqianlianmeng.utils.FileUtils;
import com.hsh.gaoqianlianmeng.utils.MyBeanUtils;
import com.hsh.gaoqianlianmeng.utils.POIExcelUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.Strings;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 洋包裹 Service
 */
@Service
@Slf4j
public class YangBGServiceImpl implements YangBGService {

@Resource
private ShopService shopService;

    /**
     * 1.生成CC/HNCC
     * 2.生成处方签数据源
     *
     * @param dateStr
     * @param shop
     * @param password
     * @return
     */
    @Override
    public Result writeAll(String dateStr, String shop, String password) {
        Result writeYangImport = writeYangImport(dateStr, shop, password);
        Result writePrescription = writePrescription(dateStr, shop);
        boolean success = false;
        if (writeYangImport.isSuccess() && writePrescription.isSuccess()) {
            success = true;
        }
        Result result = Result.create(success);
        result.setMsg(writeYangImport.getMsg() + writePrescription.getMsg());
        return result;
    }

    /**
     * 生成CC/HNCC
     *
     * @param dateStr
     * @param shop
     * @param password
     * @return
     */
    @Override
    public Result writeYangImport(String dateStr, String shop, String password) {
        if (Strings.isBlank(dateStr)) {
            dateStr = DateUtils.dateToStr(LocalDate.now(), DateTimeConstants.PURE_DATE_PATTERN);
        }
        String yangBGFolder = YangBGPathConstants.YANG_BG_FOLDER + dateStr + "\\" + shop + "\\";

        // 读取0.商品信息并转为map
        Map<String, Product> productMap = getProductMap(dateStr, shop);

        // 读取1.店铺导出
        List shopExports = getShopExports(dateStr, shop, password);

        // 转为 洋包裹导入 对象
        List<YangImport> yangImports = MyBeanUtils.copyList(shopExports, YangImport.class);
        List<YangImport> yangCCImports = new ArrayList<>();
        List<YangImport> yangHNCCImports = new ArrayList<>();
        // 将 备注中有特殊标记的订单 放入 未识别订单
        List<YangImport> unknownImports = yangImports.stream()
                .filter(y -> ShopConstants.ERROR_TYPES.contains(y.getNote()))
                .collect(Collectors.toList());

        // 去除备注中有特殊标记的订单
        yangImports = yangImports.stream()
                .filter(y -> !ShopConstants.ERROR_TYPES.contains(y.getNote()))
                .collect(Collectors.toList());

        // 设置商品名称和价格
        yangImports.forEach(y -> y.initByProduct(productMap.get(y.getProductCode())));

        // 将1.店铺导出 分配到 2.CC导入 | 2.HNCC导入 | 2.未识别订单,并按照规则排序
        assignOrder(productMap, yangImports, yangCCImports, yangHNCCImports, unknownImports);

        // 2.CC导入 拆单
        yangCCImports = splitOrder(productMap, yangCCImports);
        // 2.CC导入 商品编码前缀出现次数 降序  --->   商品数量 降序
        yangCCImports = sortByCodeIndex(yangCCImports);
        // 2.CC导入 写表
        String CCtPath = yangBGFolder + YangBGPathConstants.CC_IMPORT_FILE_NAME;
        POIExcelUtils.distinctWrite(CCtPath, yangCCImports, YangImport.class);

        // 2.HNCC导入 拆单
        yangHNCCImports = splitOrder(productMap, yangHNCCImports);
        // 2.HNCC导入 商品编码前缀出现次数 降序  --->   商品数量 降序
        yangHNCCImports = sortByCodeIndex(yangHNCCImports);
        // 2.HNCC导入 写表
        String HNCCPath = yangBGFolder + YangBGPathConstants.HNCC_IMPORT_FILE_NAME;
        POIExcelUtils.distinctWrite(HNCCPath, yangHNCCImports, YangImport.class);

        // 2.未识别订单 商品编码前缀出现次数 降序  --->   商品数量 降序
        unknownImports = sortByCodeIndex(unknownImports);
        // 2.未识别订单 写表
        String unknownPath = yangBGFolder + YangBGPathConstants.UNKNOWN_IMPORT_FILE_NAME;
        POIExcelUtils.distinctWrite(unknownPath, unknownImports, YangImport.class);

        // 写入该店铺的发货详情（txt）
        FileUtils.writeFile(yangBGFolder + YangBGPathConstants.SEND_INFO_FILE_NAME
                , getResByWriteYangImport(YangConstants.RES_TYPE_TXT, shop, shopExports, yangCCImports, yangHNCCImports, unknownImports));

        // 统计所有店铺的发货详情
        StringBuilder allShopTxtSb = new StringBuilder();
        shopService.getShop().getData();
        for (Shop s :  shopService.getShop().getData()) {
            String filePath = YangBGPathConstants.YANG_BG_FOLDER + dateStr + "\\" + s.getShopName() + "\\" + YangBGPathConstants.SEND_INFO_FILE_NAME;
            allShopTxtSb.append(FileUtils.readFile(filePath));
        }
//        for (String s : ShopConstants.SHOPS) {
//            String filePath = YangBGPathConstants.YANG_BG_FOLDER + dateStr + "\\" + s + "\\" + YangBGPathConstants.SEND_INFO_FILE_NAME;
//            allShopTxtSb.append(FileUtils.readFile(filePath));
//        }
        // 写入所有店铺的发货详情
        FileUtils.writeFile(YangBGPathConstants.YANG_BG_FOLDER + dateStr + "\\" + YangBGPathConstants.SEND_INFO_FILE_NAME
                , allShopTxtSb.toString());

        // 统计该店铺的发货详情（html格式）
        String sb = getResByWriteYangImport(YangConstants.RES_TYPE_HTML, shop, shopExports, yangCCImports, yangHNCCImports, unknownImports);
        return Result.success(sb);
    }

    /**
     * 生成处方签数据源
     *
     * @param dateStr
     * @param shop
     * @return
     */
    @Override
    public Result writePrescription(String dateStr, String shop) {
        if (Strings.isBlank(dateStr)) {
            dateStr = DateUtils.dateToStr(LocalDate.now(), DateTimeConstants.PURE_DATE_PATTERN);
        }
        String yangBGFolder = YangBGPathConstants.YANG_BG_FOLDER + dateStr + "\\" + shop + "\\";
        String HNCCPath = yangBGFolder + YangBGPathConstants.HNCC_IMPORT_FILE_NAME;
        String prescriptionPath = yangBGFolder + YangBGPathConstants.PRESCRIPTION_FILE_NAME;
        Map<String, Product> productMap = getProductMap(dateStr, shop);

        // 读取 2.HNCC 导入表格
        List<YangImport> yangHNCCImports = POIExcelUtils.read(HNCCPath, YangImport.class);

        // 3.处方签数据源 数据初始化
        List<Prescription> prescriptions = MyBeanUtils.copyList(yangHNCCImports, Prescription.class);
        for (Prescription p : prescriptions) {
            p.init(productMap.get(p.getProductCode()));
        }
        // 3.处方签数据源 写表
        POIExcelUtils.distinctWrite(prescriptionPath, prescriptions, Prescription.class);

        StringBuilder sb = new StringBuilder();
        sb.append("店铺--->").append(shop)
                .append("<br>处方签数据源--->").append(prescriptions.size())
                .append("<br>");

        return Result.success(sb.toString());
    }

    /**
     * 生成店铺发货文件
     * @param dateStr
     * @param shop
     * @return
     */
    @Override
    public Result writeShopSend(String dateStr, String shop) {
        List<YangExport> HNCCExports = POIExcelUtils.read(YangBGPathConstants.YANG_BG_FOLDER
                + dateStr + "\\" + shop + "\\" + YangBGPathConstants.HNCC_EXPORT_FILE_NAME, YangExport.class);
        HNCCExports.forEach(y -> y.setType("HNCC"));
        List<YangExport> CCExports = POIExcelUtils.read(YangBGPathConstants.YANG_BG_FOLDER
                + dateStr + "\\" + shop + "\\" + YangBGPathConstants.CC_EXPORT_FILE_NAME, YangExport.class);
        CCExports.forEach(y -> y.setType("CC"));
        List<YangExport> yangExports = new ArrayList<>();
        yangExports.addAll(HNCCExports);
        yangExports.addAll(CCExports);

        List<PDDImport> PDDImports = new ArrayList<>();
        yangExports.stream().forEach(y -> PDDImports.add(new PDDImport(y)));
        POIExcelUtils.distinctWrite(YangBGPathConstants.YANG_BG_FOLDER
                + dateStr + "\\" + shop + "\\" + YangBGPathConstants.SHOP_IMPORT_FILE_NAME, PDDImports, PDDImport.class);

        StringBuilder sb = new StringBuilder();
        sb.append("↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓")
                .append("<br>店铺---->").append(shop)
                .append("<br>HNCC---->").append(HNCCExports.size())
                .append("<br>CC---->").append(CCExports.size())
                .append("<br>发货文件---->").append(PDDImports.size())
          .append("<br>↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑");
        return Result.success(sb.toString());
    }


    // ================================私有方法开始==========================


    /**
     * 读取0.商品信息并转为map
     *
     * @param dateStr
     * @param shop
     * @return
     */
    private Map<String, Product> getProductMap(String dateStr, String shop) {
        String yangBGFolder = YangBGPathConstants.YANG_BG_FOLDER + dateStr + "\\" + shop + "\\";
        String productPath = yangBGFolder + YangBGPathConstants.PRODUCT_INFO_FILE_NAME;
        // 读取0.商品信息
        List<Product> products = POIExcelUtils.read(productPath, Product.class);
        // 订单类型map （商品编码，订单类型）
        Map<String, Product> productMap = products.stream().collect(Collectors.toMap(
                Product::getCode
                , p -> p
                , (oldProduct, newProduct) -> oldProduct));
        return productMap;
    }

    /**
     * 读取 1.店铺导出
     *
     * @param dateStr
     * @param shop
     * @param password
     * @return
     */
    private List getShopExports(String dateStr, String shop, String password) {
        String pathPre = YangBGPathConstants.YANG_BG_FOLDER
                + dateStr + "\\"
                + shop + "\\";
        String shopExportPath = pathPre + YangBGPathConstants.SHOP_EXPORT_FILE_NAME;
        if (shop.startsWith("mt")) {
            return POIExcelUtils.read(shopExportPath, MTExport.class, password);
        }
        if (shop.startsWith("pdd")) {
            List<PDDExport> pddExports = POIExcelUtils.read(shopExportPath, PDDExport.class, password);
            pddExports.stream().forEach(PDDExport::init);
            return pddExports;
        }
        return new ArrayList();
    }


    /**
     * 将1.店铺导出 分配到 2.CC导入 | 2.HNCC导入 | 2.未识别订单
     *
     * @param productMap
     * @param yangImports
     * @param yangCCImports
     * @param yangHNCCImports
     * @param unknownImports
     */
    private void assignOrder(Map<String, Product> productMap, List<YangImport> yangImports, List<YangImport> yangCCImports
            , List<YangImport> yangHNCCImports, List<YangImport> unknownImports) {

        for (YangImport y : yangImports) {
            // 获取0.商品信息中对应的商品
            Product product = productMap.get(y.getProductCode());
            // 将1.店铺导出 分配到 2.CC导入 | 2.HNCC导入 | 2.未识别订单
            if (product == null || y.getNum() < product.getHongKongMinNum()) { // 订单数量 小于 香港起发数量， 排除该订单
                unknownImports.add(y.init());
            } else if ("CC".equals(product.getType())) { // 符合条件的CC订单
                yangCCImports.add(y.CCInit());
            } else if ("HNCC".equals(product.getType())) { // 符合条件的HNCC订单
                yangHNCCImports.add(y.HNCCInit());
            } else {
                unknownImports.add(y.init());
            }
        }
    }

    /**
     * 根据前缀出现数量，确定排序的序号
     * 并按设定好的排序规则排序
     *
     * @param yangImports
     */
    private List<YangImport> sortByCodeIndex(List<YangImport> yangImports) {
        if (yangImports == null || yangImports.size() <= 2) {
            return yangImports;
        }
        // 为每个商品编码前缀匹配序号<商品编码前缀，序号>
        Map<String, Integer> codePrefixToIndexMap = getCodePrefixToIndexMap(yangImports);
        // 为每个元素 设置序号
        for (YangImport y : yangImports) {
            y.setCodeIndex(codePrefixToIndexMap.get(extractCodePrefixX(y.getProductCode())));
        }
        // 根据序号做排序
        yangImports = yangImports.stream().sorted(YangComparator::compare).collect(Collectors.toList());
        return yangImports;
    }

    /**
     * 使用正则表达式提取 -X 之前的部分
     *
     * @param code
     * @return
     */
    private static String extractCodePrefixX(String code) {
        Pattern pattern = Pattern.compile("^(.*?)-X");
        Matcher matcher = pattern.matcher(code);
        if (matcher.find()) {
            return matcher.group(1);
        }
        return code; // 如果不符合条件，返回原字符串
    }

    /**
     * 为每个商品编码前缀匹配序号
     *
     * @param yangImports
     * @return
     */
    private Map<String, Integer> getCodePrefixToIndexMap(List<YangImport> yangImports) {
        // 提取每个 code 中 -x 之前的部分
        List<String> codesPrefixX = yangImports.stream()
                .map(y -> extractCodePrefixX(y.getProductCode()))
                .collect(Collectors.toList());
        // 统计每个部分出现的次数 Map<前缀，出现次数>
        Map<String, Long> codeFrequencyMap = codesPrefixX.stream()
                .collect(Collectors.groupingBy(code -> code, Collectors.counting()));
        // 按出现次数升序排序,方便分配序号  List<Entry<前缀，出现次数>>
        List<Map.Entry<String, Long>> sortedEntries = codeFrequencyMap.entrySet().stream()
                .sorted(Map.Entry.<String, Long>comparingByValue().reversed())
                .collect(Collectors.toList());
        // 为每个商品编码前缀匹配序号
        Map<String, Integer> codePrefixToIndexMap = new HashMap<>();
        int index = 1;
        for (Map.Entry<String, Long> entry : sortedEntries) {
            codePrefixToIndexMap.put(entry.getKey(), index++);
        }
        return codePrefixToIndexMap;
    }

    /**
     * 拆单
     *
     * @param yangImports
     */
    private List<YangImport> splitOrder(Map<String, Product> productMap, List<YangImport> yangImports) {
        List<YangImport> resYangImports = new ArrayList<>();

        for (YangImport y : yangImports) {
            // 订单数量为1，不做任何改变
            if (y.getNum() <= 1) {
                resYangImports.add(y);
                continue;
            }
            // 商品编码对应的商品为空
            Product product = productMap.get(y.getProductCode());
            if (product == null) {
                continue;
            }
            // 最大免税数量：该商品免税时，最大的商品数量，向下取整
            int maxNumByMianShui = YangConstants.MAX_MIAN_SHUI_JIN_E
                    .divide(y.getUnitPrice(), 2, RoundingMode.DOWN)
                    .intValue();
            // 拆单的后缀
            int i = 1;
            while (true) {
                //
                Integer orderNum = y.getNum();
                // 最大免税数量小于0,即数量为1时已超免税额度，无需做其他操作
                // 订单数量 小于等于 最大免税数量，无需做其他操作
                if (maxNumByMianShui < 0 || orderNum <= maxNumByMianShui) {
                    resYangImports.add(y);
                    break;
                }
                // 拆单之后的元素,数量为最大免税数量
                YangImport tempY = MyBeanUtils.copy(y, YangImport.class)
                        .setNum(maxNumByMianShui)
                        .setNo(y.getNo() + "-" + i);
                resYangImports.add(tempY);

                // 数量减掉最大免税数量，再执行拆单操作
                orderNum -= maxNumByMianShui;
                y.setNum(orderNum);
                i++;
            }
        }
        return resYangImports;
    }

    /**
     * 统计该店铺的发货详情
     *
     * @param type
     * @param shop
     * @param shopExports
     * @param yangCCImports
     * @param yangHNCCImports
     * @param unknownImports
     * @return
     */
    private String getResByWriteYangImport(String type, String shop, List shopExports, List<YangImport> yangCCImports
            , List<YangImport> yangHNCCImports, List<YangImport> unknownImports) {

        StringBuilder sb = new StringBuilder();
        sb.append("↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓");
        if (Strings.isBlank(shop)) {
            return "店铺为空";
        }
        String nextLine = YangConstants.RES_TYPE_HTML.equals(type) ? "<br>" : "\n";
        sb.append(nextLine + "店铺--->").append(shop);
        // 店铺导出只在 类型为html 时返回
        if (YangConstants.RES_TYPE_HTML.equals(type)) {
            sb.append(nextLine + "店铺导出--->").append(shopExports.size());
        }
        //CC,HNCC,未识别，均在不为空时返回
        if (!yangCCImports.isEmpty()) {
            sb.append(nextLine + "生成CC订单数--->").append(yangCCImports.size());
        }
        if (!yangHNCCImports.isEmpty()) {
            sb.append(nextLine + "生成HNCC订单数--->").append(yangHNCCImports.size());
        }
        if (YangConstants.RES_TYPE_HTML.equals(type)) {
            sb.append(nextLine + "生成未识别订单数--->").append(unknownImports.size());
        }
        sb.append(nextLine + "↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑");
        return sb.toString();
    }
}
